package com.zyy;



import java.util.Stack;

/**
 * @author yinglala
 */
public class BinaryTreeOrder {

    //前序遍历
    private static void preOrder(BinaryTree t){
        if(t == null){
            return;
        }
        System.out.print(t.getData() + " ");
        preOrder(t.getLchild());
        preOrder(t.getRchild());
    }


    //中序遍历
    private static void inOrder(BinaryTree t){
        if (t == null){
            return;
        }
        inOrder(t.getLchild());
        System.out.print(t.getData() + " ");
        inOrder(t.getRchild());
    }


    //后续遍历
    private static void postOrder(BinaryTree t){
        if(t == null){
            return;
        }
        postOrder(t.getLchild());
        postOrder(t.getRchild());
        System.out.print(t.getData() + " ");
    }

    //非递归版本

    //非递归前序遍历
    private static void nonRecursivePreOrder(BinaryTree t){
        if( t == null){
            return;
        }
        Stack<BinaryTree> stack = new Stack();
        stack.push(t);

        //栈不为空 进行弹出等操作
        while (stack != null && stack.size() != 0){
            //弹出栈顶元素
            BinaryTree tmpTree = stack.pop();
            //打印
            System.out.print(tmpTree.getData() + " ");

            //若tmpTree同时存在左子树和右子树 先对右子树进行压栈 再对左子树进行压栈
            //根据栈的特性 左子树位于栈顶 先弹出左子树 再弹出右子树
            if(tmpTree.getRchild() != null){
                stack.push(tmpTree.getRchild());
            }

            if(tmpTree.getLchild() != null){
                stack.push(tmpTree.getLchild());
            }
        }

    }

    //非递归版本中序遍历
    private static void nonRecursiveInOrder(BinaryTree t){
        if(t == null){
            return;
        }
        Stack<BinaryTree> stack = new Stack();
        stack.push(t);
        //初始化辅助节点P(标识当前节点) 也是复位键
        BinaryTree p = t;
        while(stack != null && stack.size() != 0){
            //如果左孩子不为空 先压栈
            if(p != null && p.getLchild() != null){
                stack.push(p.getLchild());
                p = p.getLchild();
            }else {
                //弹出栈顶元素
                p = stack.pop();
                //打印
                System.out.print(p.getData() + " ");
                if(p.getRchild() != null){
                    stack.push(p.getRchild());
                    p = p.getRchild();
                }else {
                    //p = stack.pop(); p已经访问过了 将p设置为空
                    p = null;
                }

            }


        }
    }

    //非递归版本后序遍历
    private static void nonRecursivePostOrder(BinaryTree t){
        if(t == null){
            return;
        }
        Stack<BinaryTree> stack = new Stack();
        stack.push(t);
        BinaryTree p = t;
        BinaryTree tVisit = null;
        while(stack != null && stack.size() != 0){
            //如果左孩子不为空 先压栈
            if(p != null && p.getLchild() != null){
                stack.push(p.getLchild());
                p = p.getLchild();
            }else{
                p = stack.peek();//获取栈顶元素 并保证p不为空

                //若没有右孩子，或者右孩子已经被访问过
                if(p.getRchild() == null || p.getRchild() == tVisit){
                    //打印
                    System.out.print(p.getData() + " ");
                    //标明上个被访问的节点 防止在回溯的过程中无限访问右孩子节点
                    tVisit = p;
                    p = null;
                    //栈顶元素及其孩子节点已访问 出栈
                    stack.pop();
                }else{
                    stack.push(p.getRchild());
                    p = p.getRchild();
                }
            }


        }
    }

    public static void main(String[] args){
        BinaryTree root = new BinaryTree(1);
        BinaryTree second = new BinaryTree(2);
        BinaryTree three = new BinaryTree(3);
        BinaryTree four = new BinaryTree(4);
        BinaryTree five = new BinaryTree(5);
        BinaryTree six = new BinaryTree(6);
        BinaryTree seven = new BinaryTree(7);
        root.setLchild(second);
        root.setRchild(three);
        second.setLchild(four);
        second.setRchild(five);
        three.setLchild(six);
        three.setRchild(seven);

        System.out.println("递归先序遍历:");
        preOrder(root);
        System.out.println();
        System.out.println("递归中序遍历:");
        inOrder(root);
        System.out.println();
        System.out.println("递归后序遍历:");
        postOrder(root);
        System.out.println();
        System.out.println("非递归先序遍历:");
        nonRecursivePreOrder(root);
        System.out.println();
        System.out.println("非递归中序遍历:");
        nonRecursiveInOrder(root);
        System.out.println();
        System.out.println("非递归后序遍历:");
        nonRecursivePostOrder(root);

    }


}
